
package com.probiz.estore.common.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.probiz.estore.Constants;
import com.probiz.estore.common.helper.ConfigUtil;
import com.probiz.estore.common.model.cart.Shoppingcart;
import com.probiz.estore.common.model.cart.ShoppingcartPromotion;
import com.probiz.estore.common.model.product.Product;
import com.probiz.estore.common.model.product.ProductSku;
import com.probiz.estore.common.model.sales.Coupon;
import com.probiz.estore.common.model.sales.Gift;
import com.probiz.estore.common.model.sales.PromoRule;
import com.probiz.estore.common.model.sales.PromoRuleElement;
import com.probiz.estore.common.model.sales.PromoRuleParameter;
import com.probiz.estore.common.model.system.AppUser;
import com.probiz.estore.common.service.PromoService;
import com.probiz.estore.core.util.ContextUtil;
import com.probiz.estore.sales.engine.PRule;
import com.probiz.estore.sales.engine.PRuleEngine;
import com.probiz.estore.sales.engine.PRuleManager;
import com.probiz.estore.sales.model.EmailModel;
import com.probiz.estore.sales.service.CouponManager;
import com.probiz.estore.sales.service.GiftManager;
import com.probiz.estore.sales.service.PromoRuleElementManager;
import com.probiz.estore.sales.service.PromoRuleManager;
import com.probiz.estore.sales.service.PromoRuleParameterManager;
import com.probiz.estore.system.service.SystemConfigManager;

public class PromoServiceImpl implements PromoService {
	private static final Log	logger								= LogFactory
																			.getLog(PromoService.class);
	private static final String	SEPERATOR_BEW_SHIPPINGINFO			= ",";
	private static final String	SEPERATOR_BEW_LEVEL_AND_DISCOUNT	= "-";
	private static final String	FLAG_DISCOUNT_PERCENT				= "%";
	private static final String	FLAG_DISCOUNT_AMOUNT				= "$";
	private PromoRuleManager	promoRuleManager;
	private PRuleManager		pruleManager;
	private CouponManager		couponManager;
	private SystemConfigManager	systemConfigManager;
	private GiftManager			giftManager;
	private PromoRuleElementManager promoRuleElementManager;
	private PromoRuleParameterManager promoRuleParameterManager;

	public void setGiftManager(GiftManager giftManager) {
		this.giftManager = giftManager;
	}

	public void setPromoRuleElementManager(
			PromoRuleElementManager promoRuleElementManager) {
		this.promoRuleElementManager = promoRuleElementManager;
	}

	public void setPromoRuleParameterManager(
			PromoRuleParameterManager promoRuleParameterManager) {
		this.promoRuleParameterManager = promoRuleParameterManager;
	}

	public void setPromoRuleManager(PromoRuleManager promoRuleManager) {
		this.promoRuleManager = promoRuleManager;
	}

	public void setPruleManager(PRuleManager pruleManager) {
		this.pruleManager = pruleManager;
	}

	public void setCouponManager(CouponManager couponManager) {
		this.couponManager = couponManager;
	}

	public SystemConfigManager getSystemConfigManager() {
		return systemConfigManager;
	}

	public void setSystemConfigManager(SystemConfigManager systemConfigManager) {
		this.systemConfigManager = systemConfigManager;
	}
	

	public Shoppingcart appendPromoInfo(Shoppingcart _cart, AppUser _customer) {
		logger.debug("promoService:appendPromoInfo shoppingcart");
		Shoppingcart cart = _cart;
		PRuleEngine engine;
		if (cart.getIsUsedCoupon() == null
				|| cart.getIsUsedCoupon() != Shoppingcart.ISUSECOUPON_YES) {
			engine = new PRuleEngine(pruleManager.getCartPromotionRules());
		} else {
			Coupon coupon = new Coupon();
			coupon.setCouponNo(cart.getUsedCouponNo());
			Vector<PRule> couponPromotionRules = new Vector<PRule>();
			if (ConfigUtil.getInstance().isAllowSystemRulesWhenUseCoupon()) {
				logger
						.debug("system config-IsAllowSystemRulesWhenUseCoupon = true");
				couponPromotionRules.addAll(pruleManager
						.getCartPromotionRules());
			} else {
				logger
						.debug("system config-IsAllowSystemRulesWhenUseCoupon = false");
			}
			if (checkCoupon(coupon.getCouponNo()) == Coupon.STATE_VALID) {
				couponPromotionRules.addAll(pruleManager
						.getCouponPromotionRules(coupon));
			}
			engine = new PRuleEngine(couponPromotionRules);
		}
		try {
			cart = engine.run(cart, _customer);
			
			//重新过滤促销规则，主要是检测礼品的库存，不足时将其移除。(只针对前台)
			if(ContextUtil.getInstance().isFront()){
				this.getShoppingCartPromotions(cart);
			}
			//将coupon信息加到promotion中
			for(ShoppingcartPromotion promo: cart.getShoppingCartPromotions()){
				if(PromoRule.PROMOTION_TYPE_COUPONPROMOTION.equals(promo.getType().trim())){
					promo.setIsUsedCoupon(Constants.FLAG_TRUE);
					promo.setUsedCouponNo(cart.getUsedCouponNo());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return cart;
	}
	
	

	public ProductSku appendPromoInfo(ProductSku _sku) {
		logger.debug("promoService:appendPromoInfo sku");
		ProductSku sku = _sku;
		PRuleEngine engine = new PRuleEngine(pruleManager
				.getCatalogPromotionRules());
		try {
			sku = engine.run(sku);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sku;
	}
	

	public Collection<ProductSku> appendPromoInfo(Collection<ProductSku> _list) {
		Collection<ProductSku> list = _list;
		PRuleEngine engine = new PRuleEngine(pruleManager
				.getCatalogPromotionRules());
		try {
			list = engine.run(list);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	private Map<Integer, BigDecimal[]> parseShippingDiscountInfo(
			String _shippingDiscountInfo) {
		Map<Integer, BigDecimal[]> infos = null;
		if (_shippingDiscountInfo != null
				&& !_shippingDiscountInfo.trim().equals("")) {
			infos = new HashMap<Integer, BigDecimal[]>();
			String[] items = _shippingDiscountInfo.substring(1).split(
					SEPERATOR_BEW_SHIPPINGINFO);
			for (String item : items) {
				String[] ld = item.split(SEPERATOR_BEW_LEVEL_AND_DISCOUNT);
				if (infos.containsKey(new Integer(ld[0]))) {
					BigDecimal[] discounts = infos.get(new Integer(ld[0]));
					if (ld[1].indexOf(FLAG_DISCOUNT_PERCENT) != -1) {
						discounts[0] = discounts[0].add(new BigDecimal(ld[1]
								.substring(1)));
					} else {
						discounts[1] = discounts[1].add(new BigDecimal(ld[1]
								.substring(1)));
					}
				} else {
					BigDecimal[] discounts = new BigDecimal[2];
					if (ld[1].indexOf(FLAG_DISCOUNT_PERCENT) != -1) {
						discounts[0] = new BigDecimal(ld[1].substring(1));
						discounts[1] = new BigDecimal("0");
					} else {
						discounts[0] = new BigDecimal("0");
						discounts[1] = new BigDecimal(ld[1].substring(1));
					}
					infos.put(new Integer(ld[0]), discounts);
				}
			}
		}
		return infos;
	}

	public BigDecimal getShippingFee(String _shippingDiscountInfo,
			Integer _shippingMethodId, BigDecimal _shippingFee) {
		Map<Integer, BigDecimal[]> infos = parseShippingDiscountInfo(_shippingDiscountInfo);
		if (null != infos) {
			if (infos.containsKey(_shippingMethodId)) {
				BigDecimal[] discounts = infos.get(_shippingMethodId);
				BigDecimal shippingFeeDiscountAmount = new BigDecimal("0");
				if (discounts[0].compareTo(new BigDecimal("0")) > 0) {
					shippingFeeDiscountAmount = _shippingFee
							.multiply(discounts[0]);
				}
				shippingFeeDiscountAmount = shippingFeeDiscountAmount
						.add(discounts[1]);
				if (shippingFeeDiscountAmount.compareTo(_shippingFee) > 0) {
					return _shippingFee;
				} else {
					return _shippingFee.add(shippingFeeDiscountAmount.negate());
				}
			}
		}
		return _shippingFee;

	}
	
	public Coupon queryCouponByNo(String couponNo){
		Coupon coupon = couponManager.getCouponByNo(couponNo);
		if(null != coupon){
			coupon.setState(getState(coupon));
		}
		return coupon;
	}

	public short checkCoupon(String couponNo) {
		Coupon coupon = couponManager.getCouponByNo(couponNo);
		return getState(coupon);
	}

	private short getState(Coupon coupon) {
		if (null == coupon) {
			return Coupon.STATE_INVALID;
		}
		if (coupon.getRemainedTimes().compareTo(0) <= 0) {
			return Coupon.STATE_INVALID_REMAINEDTIMES_IS_ZERO;
		}
		PromoRule couponType = coupon.getPromoRule();
		promoRuleManager.setState(couponType);
		int state = Integer.parseInt(couponType.getState());
		if (PromoRule.STATE_INVALID == state) {
			return Coupon.STATE_INVALID_NOT_ACTIVE;
		} else if (PromoRule.STATE_FUTURE == state) {
			return Coupon.STATE_INVALID_NOT_START;
		} else if (PromoRule.STATE_PAST == state) {
			return Coupon.STATE_INVALID_IS_END;
		}
		return Coupon.STATE_VALID;
	}

	public short useCoupon(String couponNo) {
		logger.info("check coupon " + couponNo + " before use");
		short status = checkCoupon(couponNo);

		if (Coupon.STATE_VALID == status) {
			logger.info("use coupon " + couponNo);
			Coupon coupon = couponManager.getCouponByNo(couponNo);
			coupon.setRemainedTimes(coupon.getRemainedTimes() - 1);
			couponManager.save(coupon);
		}
		return status;
	}
	
	
	public void returnCoupon(String couponNo){
		Coupon coupon = couponManager.getCouponByNo(couponNo);
		if(null != coupon){
			coupon.setRemainedTimes(coupon.getRemainedTimes() + 1);
			couponManager.save(coupon);
		}
	}

	public PromoRule getCouponType(Integer gainedCouponTypeId) {
		if (null != gainedCouponTypeId) {
			return promoRuleManager.getById(gainedCouponTypeId);
		} else {
			return null;
		}
	}
	
	public Collection<ProductSku> getPromoInfoUsedInProductModule(ProductSku sku){
		logger.debug("promoService:mockAppendPromoInfo sku");
		Collection<ProductSku> skus = null;
		final Vector<PRule> cartPromotionRules = pruleManager.getCartPromotionRules();
		PRuleEngine engine = new PRuleEngine(cartPromotionRules);
		try {
			skus = engine.mockRun(sku);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return skus;
		
	}
	
	public List<PRule> getPromoInfoByProduct(Product product){
		Collection<ProductSku> promotionResults = new ArrayList<ProductSku>();
		Set<ProductSku> skus = product.getProductSkus();
		for(ProductSku sku : skus){
			Collection<ProductSku> result = getPromoInfoUsedInProductModule(sku);
			for(ProductSku item : result){
				promotionResults.add(item);
				
			}
		}
		//对结果唯一化和转换
		List<PRule> promotionList = convertAndDistinct(promotionResults);
		return promotionList;
	}
	
	private List<PRule> convertAndDistinct(Collection<ProductSku> promotionResults) {
		List<PRule> list = new ArrayList<PRule>();
		for(ProductSku sku: promotionResults){
			if(!list.contains(sku.getPrule())){
				list.add(sku.getPrule());
			}
		}
		return list;
		
	}
	
	public void doSendCoupon(Integer couponTypeId, EmailModel emailModel){
		Coupon coupon = couponManager.getIdleCoupon(couponTypeId);
		if(null == coupon){
			//产生一张类型为数字，无前缀的优惠券
			PromoRule promoRule = promoRuleManager.getById(couponTypeId);
			if(promoRule == null){
				//促销规则已删掉
				return;
			}
			coupon = couponManager.createCoupon(couponTypeId, promoRule.getAvailableCount(), 1, "");
			coupon.setPromoRule(promoRule);
		}
		couponManager.doSendCoupon(coupon, emailModel);
	}
	
	public List<Gift> getPromoInfoByProductSku(ProductSku _sku){
		ProductSku sku = this.appendPromoInfo(_sku);
		List<Gift> giftList = new ArrayList();
		Map<Integer,Gift> map = new HashMap<Integer,Gift>();
		List<PromoRule> allCartPromotionRules = promoRuleManager.getAllCatalogPromotionRulesInProcess();
		// 购物车中促销，将促销规则中礼品库存不足的从 allCartPromotionRules 数组中移除！
		List<PromoRule> promoRuleList = getShoppingcartPromotion(allCartPromotionRules);
		for (PromoRule promoRule : promoRuleList) {
			for(PromoRuleElement promoRuleElement : promoRule.getPromoRuleElements()){
				String giftId=""; Integer quantity =0;
				for(PromoRuleParameter promoRuleParameter: promoRuleElement.getPromoRuleParameters()){
					if (promoRuleParameter.getParamName().equals("GIFT")) {
						giftId = promoRuleParameter.getParamValue();
					}else if (promoRuleParameter.getParamName().equals("DISCOUNT_QUANTITY")){
						quantity = new Integer(promoRuleParameter.getParamValue());
					}
				}
				// 当礼品库存足够时，获取礼品数量
				if(giftId.length() > 0 && quantity > 0) {
					Gift gift = this.giftManager.getById(new Integer(giftId).intValue());
					if(gift.getStatus() ==0){
						continue;
					}
					//礼品相同时累计数量，否则记录当前赠送数量。结果存放在map中
					 if(map.containsKey(Integer.parseInt(giftId))){
						 Integer val = gift.getOrderSkuQuantity() + quantity;
						 gift.setOrderSkuQuantity(val);
						 map.put(gift.getId(), gift);
					 }else {
						 gift.setOrderSkuQuantity(quantity);
						 map.put(gift.getId(), gift);
					}
				}
			}
		}
		for (Gift gift : map.values()) {
			giftList.add(gift);
		}
		return giftList;
	}
	
	/**
	 * 重新过滤促销规则，检测库存，不足时将其移除。（目前只针对礼品）
	 * @param cart
	 */
	private void getShoppingCartPromotions(Shoppingcart cart) {
		List<PromoRule> promoRules = new ArrayList<PromoRule>();
		List<ShoppingcartPromotion> removeShoppingcartPromotions = new ArrayList<ShoppingcartPromotion>();
		Map<Integer,PromoRule> map = new HashMap<Integer,PromoRule>();
		for (ShoppingcartPromotion _shoppingcartPromotion : cart.getShoppingCartPromotions()) {
			PromoRule promoRule = promoRuleManager.getById(_shoppingcartPromotion.getPromoRuleId());
			promoRules.add(promoRule);
		}
		
		List<PromoRule> promoRuleList = getShoppingcartPromotion(promoRules);
		for (PromoRule _promoRule : promoRuleList) {
			map.put(_promoRule.getPromoRuleId(), _promoRule);
		}
		
		for (ShoppingcartPromotion shoppingcartPromotion : cart.getShoppingCartPromotions()) {
			if (!map.containsKey(shoppingcartPromotion.getPromoRuleId())) {
				removeShoppingcartPromotions.add(shoppingcartPromotion);
			}
		}
		cart.getShoppingCartPromotions().removeAll(removeShoppingcartPromotions);
	}
	
	/* (non-Javadoc)
	 * @see com.probiz.estore.common.service.PromoService#getShoppingcartPromotion(java.util.List)
	 */
	public List<PromoRule> getShoppingcartPromotion(List<PromoRule> promoRuleList) {
		Gift gift = new Gift();
		Map<String, Integer> map = new HashMap<String, Integer>();
		List<PromoRule> promoRules = new ArrayList<PromoRule>();
		Map<String, List<PromoRuleElement>> _elementMap = new HashMap<String, List<PromoRuleElement>>();
		List<PromoRuleElement> pres = new ArrayList<PromoRuleElement>();
		List<PromoRuleElement> promoRuleElementRemoveList = new ArrayList<PromoRuleElement>();
		
		for (PromoRule promo : promoRuleList) {
			List<PromoRuleElement> promoRuleElementList = promoRuleElementManager.findAllActionByRuleId(promo.getPromoRuleId());
			
			// 将promoRuleElementList存放在临时变量中
			List<PromoRuleElement> s = new ArrayList<PromoRuleElement>();
			s.addAll(promoRuleElementList);
			for (PromoRuleElement promoRuleElement : s) {
				if (promoRuleElement.getKind().equals("action") && promoRuleElement.getType().equals("CartGiftAction")) {
					List<PromoRuleParameter> promoRuleParameterList = promoRuleParameterManager.findAllByElementId(promoRuleElement.getPromoRuleElementId());
					//获得赠送礼品的礼品ID及赠送的数量。主要是为了下面检测库存时使用。
					String giftId=""; Integer quantity =0;
					if (promoRuleParameterList != null) {
						for (PromoRuleParameter promoRuleParameter : promoRuleParameterList) {
							if (promoRuleParameter.getParamName().equals("GIFT")) {
								giftId = promoRuleParameter.getParamValue();
							}else if (promoRuleParameter.getParamName().equals("DISCOUNT_QUANTITY")) {
								quantity = new Integer(promoRuleParameter.getParamValue());
							}
						}
					}
					//同一个规则内赠送多个礼品的处理,移除库存不足的礼品
					if(giftId.length() > 0 && quantity > 0) {
						gift = giftManager.getGiftById(new Integer(giftId).intValue());
						//礼品被删除时，从优惠赠送中移除该礼品
						if (gift == null) {
							promo.removePromoRuleElement(promoRuleElement);
							continue;
						}
						if(gift.getStatus() == 1){
							if(gift.getAvailableQuantity() != null && gift.getAvailableQuantity() < quantity){
								promo.removePromoRuleElement(promoRuleElement);
								continue;
							}else if(map.containsKey(giftId)){
								//不同规则的处理赠送同一个礼品将数量进行累加，然后总数量对比较库存，如库存不足移除的礼品
								Integer val = map.get(giftId) + quantity;
								if(gift.getAvailableQuantity() != null && gift.getAvailableQuantity() < val){
									if (quantity < map.get(giftId)){
										promo.removePromoRuleElement(promoRuleElement);
										continue;
									}else {
										val = quantity;
										if(_elementMap.containsKey(giftId)) {
											promoRuleElementRemoveList.addAll(_elementMap.get(giftId));
										}
									}
								}
								map.put(giftId, val);
							} else {
								map.put(giftId, quantity);
							}
						}else{
							promo.removePromoRuleElement(promoRuleElement);
							continue;
						}
						if (_elementMap.containsKey(giftId)) {
							pres.add(promoRuleElement);
						} else {
							pres = new ArrayList<PromoRuleElement>();
							pres.add(promoRuleElement);
						}
						_elementMap.put(giftId, pres);
					}
				}
			}
		}
		
		// 移除重复的礼品
		for (PromoRule promoRule : promoRuleList) {
			for (PromoRuleElement _promoRuleElement : promoRuleElementRemoveList) {	
				promoRule.removePromoRuleElement(_promoRuleElement);
			}
			
			//检测过礼品的库存后，检查规则里还是否存在赠送操作，如果没有则移除该促销规则（即不触发）
			Integer countAction = 0;
			for (PromoRuleElement promoRuleElement : promoRule.getPromoRuleElements()) {
				if (promoRuleElement.getKind().equals("action")) {
					countAction += 1;
				}
			}
			if(countAction <1){
				promoRules.add(promoRule);// 没有赠送操作的促销规则
			}
		}
		if(promoRules.size()>0){// 移除不存在优惠操作的促销规则
			promoRuleList.removeAll(promoRules);
		}
		return promoRuleList;
	}
	
}
